<template>
  <div class="meeting-page">
    <el-card class="meeting-card">
      <template #header>
        <div class="card-header">
          <span>会议选择</span>
        </div>
      </template>

      <!-- 会议列表与WebSocket连接状态 -->
      <div class="control-panel">
        <div class="status">
          连接状态: 
          <el-tag :type="wsConnected ? 'success' : 'danger'">
            {{ wsConnected ? '已连接' : '未连接' }}
          </el-tag>
          <span v-if="wsConnected && activeMode === 'microphone'" class="recording-status">
            <i class="el-icon-microphone" :class="{ 'is-recording': isRecording }"></i>
            {{ isRecording ? '正在录音' : '麦克风未启动' }}
          </span>
        </div>
        
        <!-- 会议选择部分 -->
        <div class="meeting-selection">
          <h3>请选择要连接的会议：</h3>
          <el-table :data="meetings" stripe style="width: 100%" v-loading="loading" @row-click="handleMeetingSelect">
            <el-table-column label="会议名称" prop="name"></el-table-column>
            <el-table-column label="会议ID" prop="id" width="300"></el-table-column>
            <el-table-column label="操作" width="120">
              <template #default="scope">
                <el-button 
                  size="small" 
                  type="primary" 
                  @click.stop="connectToMeeting(scope.row)"
                >
                  连接
                </el-button>
              </template>
            </el-table-column>
          </el-table>
          
          <!-- 分页 -->
          <div class="pagination-container">
            <el-pagination
              v-model:current-page="queryParams.page"
              v-model:page-size="queryParams.size"
              :page-sizes="[10, 20, 30, 50]"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total"
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
            />
          </div>
        </div>
      </div>

      <!-- 连接按钮 -->
      <div class="buttons" v-if="selectedMeeting">
        <el-tabs v-model="activeMode" @tab-change="handleModeChange">
          <el-tab-pane label="文件模式" name="file">
            <div class="mode-content">
              <el-upload
                class="upload-demo"
                action=""
                :auto-upload="false"
                :show-file-list="false"
                accept=".pcm,audio/*"
                @change="handleFileChange"
              >
                <el-button type="primary">选择音频文件</el-button>
              </el-upload>
              <div class="audio-info" v-if="audioFile">
                <p>已选择音频文件: {{ audioFile.name }}</p>
                <p>文件大小: {{ (audioFile.size / 1024).toFixed(2) }} KB</p>
              </div>
              
              <div class="action-buttons" v-if="activeMode === 'file'">
                <el-button 
                  type="success" 
                  @click="startSending" 
                  :disabled="!wsConnected || isSending || !canStartSending"
                >
                  开始发送
                </el-button>
                <el-button 
                  type="danger" 
                  @click="stopSending" 
                  :disabled="!isSending"
                >
                  停止发送
                </el-button>
              </div>
            </div>
          </el-tab-pane>
          <el-tab-pane label="麦克风模式" name="microphone">
            <div class="mode-content">
              <div class="mic-info">
                <p>麦克风模式下，连接WebSocket后会自动开始录音并发送数据</p>
                <p>断开连接时会自动停止录音</p>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
        
        <div class="connection-button">
          <el-button 
            :type="wsConnected ? 'danger' : 'primary'" 
            @click="wsConnected ? disconnectWebSocket() : connectWebSocket()" 
            size="large"
          >
            {{ wsConnected ? '断开连接' : '连接WebSocket' }}
          </el-button>
        </div>
      </div>

      <!-- 发送状态 -->
      <div class="sending-status" v-if="(isSending && activeMode === 'file') || (wsConnected && activeMode === 'microphone')">
        <el-progress 
          v-if="activeMode === 'file'"
          :percentage="sendProgress" 
          :format="progressFormat"
          status="success"
        />
        <div v-else class="data-stats">
          <div class="stat-item">
            <span class="label">已发送数据:</span>
            <span class="value">{{ (totalBytesSent / 1024).toFixed(2) }} KB</span>
          </div>
          <div class="stat-item">
            <span class="label">发送速率:</span>
            <span class="value">{{ sendRate.toFixed(2) }} KB/s</span>
          </div>
          <div class="stat-item">
            <span class="label">音频电平:</span>
            <el-progress :percentage="audioLevel * 100" :stroke-width="8" :show-text="false"></el-progress>
          </div>
        </div>
      </div>

      <!-- 接收到的文字结果显示 -->
      <div class="result-panel" v-if="wsConnected">
        <div class="result-header">
          <span>识别结果：</span>
          <el-button type="primary" link @click="clearResults">清空</el-button>
        </div>
        <el-scrollbar height="200px">
          <div class="result-content">
            <p v-for="(text, index) in recognitionResults" :key="index">
              {{ text }}
            </p>
          </div>
        </el-scrollbar>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, onUnmounted, computed, watch, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { getMeetingList, Meeting, MeetingQuery } from '@/api/meeting'

// 会议列表和选择相关
const meetings = ref<Meeting[]>([])
const loading = ref(false)
const total = ref(0)
const selectedMeeting = ref<Meeting | null>(null)
const queryParams = ref<MeetingQuery>({
  page: 1,
  size: 10
})

// 获取会议列表
const fetchMeetings = async () => {
  loading.value = true
  try {
    const response = await getMeetingList(queryParams.value)
    meetings.value = response.current_data
    total.value = response.total_record
  } catch (error) {
    console.error('获取会议列表失败:', error)
    ElMessage.error('获取会议列表失败')
  } finally {
    loading.value = false
  }
}

// 处理会议选择
const handleMeetingSelect = (row: Meeting) => {
  selectedMeeting.value = row
  ElMessage.success(`已选择会议: ${row.name}`)
}

// 连接到指定会议
const connectToMeeting = (meeting: Meeting) => {
  selectedMeeting.value = meeting
  if (!wsConnected.value) {
    connectWebSocket()
  }
}

// 分页处理
const handleSizeChange = (size: number) => {
  queryParams.value.size = size
  fetchMeetings()
}

const handleCurrentChange = (page: number) => {
  queryParams.value.page = page
  fetchMeetings()
}

// 组件加载时获取会议列表
onMounted(() => {
  fetchMeetings()
})

// 模式选择
const activeMode = ref('file')
const isRecording = ref(false)

// WebSocket连接状态
const wsConnected = ref(false)
const ws = ref<WebSocket | null>(null)
const isSending = ref(false)
const audioFile = ref<File | null>(null)
const sendProgress = ref(0)
const recognitionResults = ref<string[]>([])
const totalBytesSent = ref(0)
const sendRate = ref(0)
const audioLevel = ref(0)
let lastSendTime = Date.now()
let lastBytesSent = 0

// 文件模式相关
const audioData = ref<Int16Array | null>(null)
const SAMPLE_RATE = 16000 // 采样率
const CHUNK_SIZE = 1600 // 每100ms发送的数据量
const SEND_INTERVAL = 100 // 发送间隔(ms)
let currentPosition = 0
let sendTimer: number | null = null

// 麦克风模式相关
let audioContext: AudioContext | null = null
let mediaStream: MediaStream | null = null
let audioSource: MediaStreamAudioSourceNode | null = null

// 计算是否可以开始发送
const canStartSending = computed(() => {
  if (activeMode.value === 'file') {
    return !!audioFile.value && !!audioData.value
  } else {
    return true
  }
})

// 监听模式变化
watch(activeMode, (newMode) => {
  if (newMode === 'microphone' && wsConnected.value && !isRecording.value) {
    // 如果切换到麦克风模式且已连接WebSocket，则自动开始录音
    initMicrophone()
  } else if (newMode === 'file' && isRecording.value) {
    // 如果从麦克风模式切换到文件模式，则停止录音
    stopRecording()
  }
})

// 处理模式切换
const handleModeChange = () => {
  if (isSending.value) {
    stopSending()
  }
}

// 连接WebSocket
const connectWebSocket = () => {
  if (!selectedMeeting.value) {
    ElMessage.warning('请先选择一个会议')
    return
  }

  try {
    console.log('开始连接WebSocket...')
    ws.value = new WebSocket(`ws://localhost:8006/publisher/${selectedMeeting.value.id}`) 

    ws.value.onopen = () => {
      wsConnected.value = true
      console.log('WebSocket连接成功')
      ElMessage.success('WebSocket连接成功')
      
      // 如果是麦克风模式，自动开始录音
      if (activeMode.value === 'microphone') {
        initMicrophone()
      }
    }

    ws.value.onclose = (event) => {
      wsConnected.value = false
      console.log('WebSocket连接关闭:', {
        code: event.code,
        reason: event.reason,
        wasClean: event.wasClean
      })
      ElMessage.warning(`WebSocket连接已关闭 (${event.code}: ${event.reason || '未知原因'})`)
      if (isSending.value) {
        stopSending()
      }
      if (isRecording.value) {
        stopRecording()
      }
    }

    ws.value.onerror = (error) => {
      console.error('WebSocket错误:', error)
      ElMessage.error('WebSocket连接错误')
    }

    ws.value.onmessage = (event) => {
      console.log('收到WebSocket消息:', event.data)
      // 处理接收到的识别结果
      try {
        const result = JSON.parse(event.data)
        if (result.text) {
          console.log('收到识别结果:', result.text)
          recognitionResults.value.push(result.text)
          
          // 自动滚动到底部
          setTimeout(() => {
            const scrollbar = document.querySelector('.el-scrollbar__wrap')
            if (scrollbar) {
              scrollbar.scrollTop = scrollbar.scrollHeight
            }
          }, 100)
        }
      } catch (error) {
        console.error('处理识别结果出错:', error)
      }
    }
  } catch (error) {
    console.error('连接WebSocket失败:', error)
    ElMessage.error('连接WebSocket失败')
  }
}

// 断开WebSocket
const disconnectWebSocket = () => {
  if (ws.value) {
    ws.value.close()
    ws.value = null
  }
  
  if (isSending.value) {
    stopSending()
  }
  
  if (isRecording.value) {
    stopRecording()
  }
  
  wsConnected.value = false
  ElMessage.info('已断开WebSocket连接')
}

// 处理文件选择
const handleFileChange = async (file: any) => {
  // 检查文件扩展名
  const fileName = file.raw.name.toLowerCase()
  if (!fileName.endsWith('.pcm') && !file.raw.type.startsWith('audio/')) {
    ElMessage.error('请上传PCM格式或音频格式的文件')
    return
  }

  audioFile.value = file.raw
  currentPosition = 0
  sendProgress.value = 0
  
  try {
    // 读取文件内容
    const arrayBuffer = await file.raw.arrayBuffer()
    // 假设文件是16位PCM格式
    audioData.value = new Int16Array(arrayBuffer)
    ElMessage.success('音频文件加载成功')
  } catch (error) {
    console.error('音频文件加载失败:', error)
    ElMessage.error('音频文件加载失败')
  }
}

// 初始化麦克风
const initMicrophone = async () => {
  try {
    console.log('开始初始化麦克风...')
    if (isRecording.value) {
      console.log('麦克风已经在录音中，跳过初始化')
      return true
    }
    
    // 获取麦克风权限
    console.log('请求麦克风权限...')
    mediaStream = await navigator.mediaDevices.getUserMedia({ 
      audio: {
        echoCancellation: true,
        noiseSuppression: true,
        autoGainControl: true,
        sampleRate: SAMPLE_RATE
      } 
    })
    console.log('麦克风权限获取成功')
    
    // 创建音频上下文
    console.log('创建音频上下文...')
    audioContext = new AudioContext({
      sampleRate: SAMPLE_RATE
    })
    console.log('音频上下文创建成功，采样率:', audioContext.sampleRate)
    
    // 创建音频源
    console.log('创建音频源...')
    audioSource = audioContext.createMediaStreamSource(mediaStream)
    console.log('音频源创建成功')
    
    // 创建脚本处理器节点
    const scriptNode = audioContext.createScriptProcessor(2048, 1, 1)
    console.log('音频处理节点创建成功，缓冲区大小:', 2048)
    
    // 设置音频处理回调
    scriptNode.onaudioprocess = (audioProcessingEvent) => {
      if (!wsConnected.value || !ws.value) {
        console.log('WebSocket未连接，跳过数据发送')
        return
      }
      
      // 获取输入数据
      const inputBuffer = audioProcessingEvent.inputBuffer
      const inputData = inputBuffer.getChannelData(0)
      
      // 转换为16位整数
      const pcmData = new Int16Array(inputData.length)
      for (let i = 0; i < inputData.length; i++) {
        const s = Math.max(-1, Math.min(1, inputData[i]))
        pcmData[i] = s < 0 ? s * 0x8000 : s * 0x7FFF
      }
      
      console.log('收到音频数据:', {
        length: pcmData.length,
        sampleRate: audioContext?.sampleRate,
        timestamp: new Date().toISOString(),
        bufferSize: pcmData.buffer.byteLength,
        firstFewSamples: Array.from(pcmData.slice(0, 5))
      })
      
      try {
        // 发送数据
        ws.value.send(pcmData.buffer)
        console.log('音频数据发送成功，大小:', pcmData.length * 2, '字节')
        
        // 更新统计信息
        const bytesSent = pcmData.length * 2 // 16位 = 2字节
        updateSendStats(bytesSent)
        
        // 计算音频电平
        let sum = 0
        for (let i = 0; i < pcmData.length; i++) {
          sum += Math.abs(pcmData[i])
        }
        audioLevel.value = Math.min(1, (sum / pcmData.length) / 10000)
      } catch (error) {
        console.error('发送音频数据失败:', error)
      }
    }
    
    // 连接节点
    console.log('连接音频节点...')
    audioSource.connect(scriptNode)
    scriptNode.connect(audioContext.destination)
    console.log('音频节点连接成功')
    
    isRecording.value = true
    ElMessage.success('麦克风录音已开始')
    return true
  } catch (error) {
    console.error('初始化麦克风失败:', error)
    ElMessage.error('无法访问麦克风')
    return false
  }
}

// 停止录音
const stopRecording = () => {
  console.log('开始停止录音...')
  isRecording.value = false
  
  // 停止并清理音频资源
  if (audioSource) {
    console.log('断开音频源...')
    audioSource.disconnect()
    audioSource = null
  }
  
  if (audioContext) {
    console.log('关闭音频上下文...')
    audioContext.close()
    audioContext = null
  }
  
  if (mediaStream) {
    console.log('停止媒体流...')
    mediaStream.getTracks().forEach(track => {
      console.log('停止轨道:', track.kind, track.label)
      track.stop()
    })
    mediaStream = null
  }
  
  ElMessage.info('麦克风录音已停止')
  console.log('录音已完全停止')
}

// 更新发送统计信息
const updateSendStats = (bytesSent: number) => {
  const now = Date.now()
  const timeDiff = (now - lastSendTime) / 1000 // 转换为秒
  
  // 更新总发送量
  totalBytesSent.value += bytesSent
  
  // 计算发送速率
  sendRate.value = (bytesSent / timeDiff) / 1024 // KB/s
  
  // 更新上次发送时间
  lastSendTime = now
  lastBytesSent = bytesSent
}

// 开始发送音频数据
const startSending = async () => {
  if (!wsConnected.value) return

  if (activeMode.value === 'file') {
    // 文件模式
    if (!audioData.value) return

    isSending.value = true
    
    // 使用定时器模拟实时发送
    sendTimer = window.setInterval(() => {
      if (currentPosition >= audioData.value!.length) {
        stopSending()
        return
      }

      // 获取当前块的数据
      const endPosition = Math.min(currentPosition + CHUNK_SIZE, audioData.value!.length)
      const chunk = audioData.value!.slice(currentPosition, endPosition)
      
      // 发送数据
      ws.value?.send(chunk.buffer)
      
      // 更新统计信息
      const bytesSent = chunk.length * 2 // 16位 = 2字节
      updateSendStats(bytesSent)
      
      // 更新位置和进度
      currentPosition += CHUNK_SIZE
      sendProgress.value = Math.min(100, (currentPosition / audioData.value!.length) * 100)
    }, SEND_INTERVAL)
    
    ElMessage.success('开始发送文件音频数据')
  }
}

// 停止发送
const stopSending = () => {
  if (activeMode.value === 'file') {
    // 文件模式
    if (sendTimer) {
      window.clearInterval(sendTimer)
      sendTimer = null
    }
    currentPosition = 0
    sendProgress.value = 0
    isSending.value = false
    ElMessage.info('已停止发送音频数据')
  }
}

// 清空结果
const clearResults = () => {
  recognitionResults.value = []
}

// 格式化进度条显示
const progressFormat = (percentage: number) => {
  return `${percentage.toFixed(1)}%`
}

// 组件卸载时清理
onUnmounted(() => {
  if (isSending.value) {
    stopSending()
  }
  
  if (isRecording.value) {
    stopRecording()
  }
  
  if (ws.value) {
    ws.value.close()
    ws.value = null
  }
})
</script>

<style scoped>
.meeting-page {
  padding: 20px;
}

.meeting-card {
  max-width: 800px;
  margin: 0 auto;
}

.card-header {
  font-size: 18px;
  font-weight: bold;
}

.control-panel {
  margin-bottom: 20px;
}

.status {
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 15px;
}

.meeting-selection {
  margin: 20px 0;
}

.pagination-container {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}

.recording-status {
  display: flex;
  align-items: center;
  gap: 5px;
  color: #409EFF;
}

.is-recording {
  animation: pulse 1.5s infinite;
  color: #67C23A;
}

@keyframes pulse {
  0% { opacity: 1; }
  50% { opacity: 0.4; }
  100% { opacity: 1; }
}

.buttons {
  margin-bottom: 15px;
}

.connection-button {
  display: flex;
  justify-content: center;
  margin-top: 20px;
}

.mode-content {
  padding: 20px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.action-buttons {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin-top: 20px;
}

.mic-info {
  margin: 10px 0;
  text-align: center;
  color: #606266;
  background-color: #f5f7fa;
  padding: 15px;
  border-radius: 4px;
  width: 100%;
}

.audio-info {
  margin: 15px 0;
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
  width: 100%;
}

.sending-status {
  margin: 20px 0;
}

.data-stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 30px;
}

.stat-item {
  display: flex;
  align-items: center;
  min-width: 200px;
}

.stat-item:nth-child(3) {
  flex-basis: 100%;
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.stat-item:nth-child(3) .el-progress {
  width: 100%;
  margin-top: 5px;
}

.stat-item .label {
  margin-right: 8px;
  color: #606266;
}

.stat-item .value {
  font-weight: bold;
  color: #409EFF;
}

.result-panel {
  margin-top: 20px;
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.result-content {
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.result-content p {
  margin: 5px 0;
  line-height: 1.5;
}
</style>
